"""
自定义日志处理器模块

提供两种增强型日志处理器：
1. CustomRotatingFileHandler - 基于文件大小的日志轮转
2. CustomTimedRotatingFileHandler - 基于时间的日志轮转

特性：
- 智能文件名处理，保留日期部分
- 精确控制备份文件数量
- 线程安全的文件轮转操作
"""

import os
import glob
import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler

class CustomRotatingFileHandler(RotatingFileHandler):
    """
    自定义基于文件大小的日志轮转处理器

    继承自RotatingFileHandler，增强功能：
    - 改进文件名处理逻辑，保留原始文件名中的日期部分
    - 精确控制备份文件数量
    - 线程安全的轮转操作

    使用示例:
        handler = CustomRotatingFileHandler(
            'app.log',
            maxBytes=10*1024*1024,  # 10MB
            backupCount=5
        )
    """
    def __init__(self, filename, **kwargs):
        try:
            super().__init__(filename, **kwargs)
            self.namer = self.custom_namer
        except Exception as e:
            import traceback
            error_msg = f"创建CustomRotatingFileHandler时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            raise RuntimeError(error_msg) from e

    def custom_namer(self, name):
        try:
            if name.endswith(".log"):
                return name
            # 标准命名格式: prod.log.1, prod.log.2 等
            base, ext = os.path.splitext(self.baseFilename)
            num = int(name.split(".")[-2])
            return f"{base}.{num}{ext}"
        except Exception as e:
            import traceback
            error_msg = f"处理日志文件名时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            # 返回原始名称作为后备方案
            return name

    def doRollover(self):
        try:
            if self.stream:
                self.stream.close()
                self.stream = None

            # 删除最旧的备份文件
            if self.backupCount > 0:
                oldest = f"{os.path.splitext(self.baseFilename)[0]}.{self.backupCount}{os.path.splitext(self.baseFilename)[1]}"
                if os.path.exists(oldest):
                    os.remove(oldest)

            # 重命名其他备份文件
            for i in range(self.backupCount - 1, 0, -1):
                src = f"{os.path.splitext(self.baseFilename)[0]}.{i}{os.path.splitext(self.baseFilename)[1]}"
                if os.path.exists(src):
                    dst = f"{os.path.splitext(self.baseFilename)[0]}.{i+1}{os.path.splitext(self.baseFilename)[1]}"
                    os.rename(src, dst)

            # 重命名当前日志文件
            dst = f"{os.path.splitext(self.baseFilename)[0]}.1{os.path.splitext(self.baseFilename)[1]}"
            if os.path.exists(self.baseFilename):
                os.rename(self.baseFilename, dst)

            self.stream = self._open()
        except Exception as e:
            import traceback
            error_msg = f"执行日志轮转操作时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            # 重新抛出异常，让上层处理
            raise RuntimeError(error_msg) from e

class CustomTimedRotatingFileHandler(TimedRotatingFileHandler):
    """
    自定义基于时间的日志轮转处理器

    继承自TimedRotatingFileHandler，增强功能：
    - 改进文件名处理逻辑，保留原始文件名中的日期部分
    - 精确控制备份文件数量
    - 支持多种时间间隔(S秒/M分/H时/D天)
    - 线程安全的轮转操作

    使用示例:
        handler = CustomTimedRotatingFileHandler(
            'app.log',
            when='D',  # 每天轮转
            backupCount=7  # 保留7天日志
        )
    """
    def __init__(self, filename, **kwargs):
        try:
            super().__init__(filename, **kwargs)
            self.namer = self.custom_namer
        except Exception as e:
            import traceback
            error_msg = f"创建CustomTimedRotatingFileHandler时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            raise RuntimeError(error_msg) from e

    def custom_namer(self, name):
        try:
            if name.endswith(".log"):
                return name
            # 保持日期部分不变，只修改序号
            base = os.path.splitext(self.baseFilename)[0]
            if '_' in base.rsplit('/', 1)[-1]:  # 检查文件名部分是否包含下划线(日期)
                base_parts = base.rsplit('_', 1)
                prefix = base_parts[0]
                date_part = base_parts[1]
                num = int(name.split(".")[-2])
                return f"{prefix}_{date_part}.{num}.log"
            else:
                base, ext = os.path.splitext(self.baseFilename)
                num = int(name.split(".")[-2])
                return f"{base}.{num}{ext}"
        except Exception as e:
            import traceback
            error_msg = f"处理时间轮转日志文件名时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            # 返回原始名称作为后备方案
            return name

    def doRollover(self):
        try:
            super().doRollover()
            # 确保备份文件不超过指定数量
            if self.backupCount > 0:
                files = sorted(
                    glob.glob(f"{os.path.splitext(self.baseFilename)[0]}.*{os.path.splitext(self.baseFilename)[1]}"),
                    key=lambda x: int(x.split(".")[-2]),
                    reverse=True
                )
                for f in files[self.backupCount:]:
                    try:
                        os.remove(f)
                    except OSError:
                        pass
        except Exception as e:
            import traceback
            error_msg = f"执行时间轮转操作时发生错误: {str(e)}"
            logging.error(error_msg)
            logging.error(traceback.format_exc())
            # 重新抛出异常，让上层处理
            raise RuntimeError(error_msg) from e